﻿/*
   Copyright 2012 University of Southampton

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

using System;
using System.Collections.Generic;
using System.Linq;

namespace uk.ac.soton.ses.layouts
{
    internal class GraphData_XY
    {
        internal class XYValues
        {
            public string X { get; set; }
            public string Y { get; set; }

            //Optional values for graph
            public string XPointName { get; set; }
            public string YPointName { get; set; }
            public string XExperimentID { get; set; }
            public string XParameterID { get; set; }
            public string YExperimentID { get; set; }
            public string YParameterID { get; set; }

            public XYValues(string X, string Y)
            {
                this.X = X;
                this.Y = Y;
            }
        }

        private Dictionary<string, List<XYValues>> _baseGraphData;
        private List<string> _seriesStrings;
        private string _graphType;

        public List<string> SeriesStrings { get { return this._seriesStrings; } set { this._seriesStrings = value; } }

        public string XAxisTitle { get; set; }
        public string YAxisTitle { get; set; }
        public string ChartTitle { get; set; }

        public string FormattedGraphType
        {
            get { return "type: '" + this._graphType + "'"; }
        }

        public string FormattedChartTitle
        {
            get
            {
                if (this.ChartTitle!=null && this.ChartTitle.Length > 0)
                {
                    return string.Format("title: {{ text:'{0}'}}", this.ChartTitle);
                }
                else
                {
                    return "";
                }
            }
        }

        public string FormattedXAxisTitle
        {
            get
            {
                if (this.XAxisTitle!=null && this.XAxisTitle.Length > 0)
                {
                    return string.Format("title: {{ text:'{0}'}}", this.XAxisTitle);
                }
                else
                {
                    return "";
                }
            }
        }
        public string FormattedYAxisTitle
        {
            get
            {
                if (this.YAxisTitle!=null && this.YAxisTitle.Length > 0)
                {
                    return string.Format("title: {{ text:'{0}'}}", this.YAxisTitle);
                }
                else
                {
                    return "";
                }
            }
        }

        public string FormattedSeriesString
        {
            get
            {
                return "series: [" + string.Join(",", this._seriesStrings.ToArray()) + "]";
            }
        }

        public string FormattedTooltipString
        {
            get
            {
                return "tooltip: { useHTML:true, formatter: function() { "
                    + "return '<table style=\"vertical-align:middle;font-size:7pt;\"><tr><td colspan=\"3\"><span style=\"border: grey 1px solid;padding:0px 2px;color:' + this.series.color + '\">' + this.series.name + '</span></td><td>Exp</td><td>Param</td>"
                    + "<tr><td>x</td><td>' + this.point.xpointname + '</td><td style=\"color:' + this.series.color + '\"><b>' + this.point.x + '</b></td><td>' + this.point.xexpid + '</td><td>' + this.point.xparamid + '</td></tr>"
                    + "<tr><td>y</td><td>' + this.point.ypointname + '</td><td style=\"color:' + this.series.color + '\"><b>' + this.point.y + '</b><td>' + this.point.yexpid + '</td><td>' + this.point.yparamid + '</td></tr></table>'; } }";
            }
        }

        public string FormattedJavaScript
        {
            get
            {
                string js = @"<script type='text/javascript'>
            $(function () {
                $('#graphcontainer').highcharts("
                +   "{"
                +       "chart: {" 
                +           this.GetFirstStructure(this.FormattedGraphType)
                +       "}"
                +       ",xAxis: {"
                +           this.GetFirstStructure(this.FormattedXAxisTitle)
                +       "}"
                +       ",yAxis: {"
                +           this.GetFirstStructure(this.FormattedYAxisTitle)
                +       "}"
                +       this.GetNextStructure(this.FormattedSeriesString)
                +       this.GetNextStructure(this.FormattedChartTitle)
                +       this.GetNextStructure(this.FormattedTooltipString)
                +   "}"
                + @");
            });
            </script>";
                return js;
            }
        }

        /// <summary>
        /// At the moment, this just returns the string, but eventually it might add text like an opening brace.
        /// </summary>
        /// <param name="s">The string</param>
        /// <returns>The string</returns>
        public string GetFirstStructure(string s)
        {
            return s;
        }

        /// <summary>
        /// If the string is blank, an empty string is returned, otherwise a comma is prepended
        /// </summary>
        /// <param name="s">The string</param>
        /// <returns>The string with a comma prepended, or an empty string</returns>
        public string GetNextStructure(string s)
        {
            if (!string.IsNullOrEmpty(s))
            {
                return "," + s;
            }
            else
            {
                return "";
            }
        }

        public void AddStringToListIfNotEmpty(string stringToCheckAndAdd, string formatString, List<string> listToEdit)
        {
            if (!string.IsNullOrEmpty(stringToCheckAndAdd))
            {
                listToEdit.Add(string.Format(formatString, stringToCheckAndAdd));
            }
        }

        public GraphData_XY(Dictionary<string, List<XYValues>> graphData, string graphType)
        {
            //Store the data we have been passed
            this._baseGraphData = graphData;
            this._graphType = graphType;

            //Default these to something sensible
            this._seriesStrings = new List<string>();

            //Try and populate the function string and the series strings
            switch (this._graphType)
            {
                case "scatter":
                    this.GetSeriesDataForScatterGraph();
                    break;
                default:
                    throw new Exception("Incorrect graph type requested");
            }
        }

        private void GetSeriesDataForScatterGraph()
        {
            List<KeyValuePair<string, List<XYValues>>> graphDataList = this._baseGraphData.ToList();

            List<string> seriesStrings = new List<string>();

            for (int i = 0; i < graphDataList.Count; i++)
            {
                List<string> parameter_values = new List<string>();
                KeyValuePair<string, List<XYValues>> dataset = graphDataList[i];
                List<XYValues> dataset_values= dataset.Value;

                foreach (XYValues dataset_value in dataset_values)
                {
                    List<string> additionalInfoList =new List<string>();
                    this.AddStringToListIfNotEmpty(dataset_value.XExperimentID,"xexpid:{0}",additionalInfoList);
                    this.AddStringToListIfNotEmpty(dataset_value.YExperimentID,"yexpid:{0}",additionalInfoList);
                    this.AddStringToListIfNotEmpty(dataset_value.XParameterID, "xparamid:{0}", additionalInfoList);
                    this.AddStringToListIfNotEmpty(dataset_value.YParameterID, "yparamid:{0}", additionalInfoList);
                    this.AddStringToListIfNotEmpty(dataset_value.XPointName, "xpointname:'{0}'", additionalInfoList);
                    this.AddStringToListIfNotEmpty(dataset_value.YPointName, "ypointname:'{0}'", additionalInfoList);

                    string finalAdditionalInfo = string.Join(",", additionalInfoList.ToArray());
                    string newParameterValue = string.Format("{{x:{0},y:{1}{2}}}", dataset_value.X, dataset_value.Y, this.GetNextStructure(finalAdditionalInfo));
                    parameter_values.Add(newParameterValue);
                }

                string series_data = string.Join(",", parameter_values.ToArray());
                string seriesString = string.Format("{{name: '{0}', data:[{1}] }}", dataset.Key, series_data);
                seriesStrings.Add(seriesString);
            }
            this.SeriesStrings = seriesStrings;
        }
    }
}
